<template>
  <el-card
    v-if="item"
    class="control"
    :style="styleSet"
    :body-style="{ padding: '5px', height: item.IsShowHead ? (contentHeight - 55.4) + 'px' : contentHeight + 'px' }"
  >
    <div v-if="item.IsShowHead" slot="header">
      <span>{{ title }}</span>
    </div>
    <div v-if="item.IsConfig" ref="chartBody" class="chartBody" />
    <div v-else class="null" @click="edit">
      <span>点击配置控件</span>
    </div>
  </el-card>
</template>

<script>
import {
  Chart
} from '@/customForm/api/pageCalculate'
export default {
  components: {},
  props: {
    id: {
      type: String,
      default: null
    },
    width: {
      type: Number,
      default: null
    },
    height: {
      type: Number,
      default: null
    },
    item: {
      type: Object,
      default: null
    },
    title: {
      type: String,
      default: null
    },
    show: {
      type: String,
      default: null
    },
    contentWidth: {
      type: Number,
      default: null
    },
    extend: {
      type: Object,
      default: null
    },
    search: {
      type: Array,
      default: null
    }
  },
  data() {
    return {
      styleSet: {
        width: '100px',
        height: '70px'
      },
      contentHeight: 70,
      source: null,
      valueStyle: null,
      control: null,
      curChart: null
    }
  },
  computed: {
    isDark() {
      return this.$store.getters.theme === 'dark'
    }
  },
  watch: {
    width: {
      handler(val) {
        if (val && this.height && this.contentWidth) {
          this.init()
        }
      },
      immediate: true
    },
    height: {
      handler(val) {
        if (val && this.width && this.contentWidth) {
          this.init()
        }
      },
      immediate: true
    },
    contentWidth: {
      handler(val) {
        if (val && this.height && this.width) {
          this.init()
        }
      },
      immediate: true
    },
    item: {
      handler(val) {
        if (val) {
          this.reset()
        } else {
          this.control = null
        }
      },
      immediate: true
    },
    'item.Legend': {
      handler(val) {
        if (val) {
          this.initCharts()
        }
      },
      immediate: false,
      deep: true
    },
    'item.Title': {
      handler(val) {
        this.initCharts()
      },
      immediate: false,
      deep: true
    },
    'item.YAxis': {
      handler(val) {
        this.initCharts()
      },
      immediate: false,
      deep: true
    },
    'item.MarkLine': {
      handler(val) {
        this.initCharts()
      },
      immediate: false,
      deep: true
    },
    isDark: {
      handler(val) {
        if (this.source) {
          this.initCharts()
        }
      },
      immediate: false
    }
  },
  mounted() { },
  methods: {
    init() {
      this.contentHeight = (14 * this.height)
      let width = 0
      if (this.width === 23) {
        width = Math.round(this.contentWidth * 2 / 3) - 12
      } else {
        width = Math.round(this.contentWidth / this.width) - 12
      }
      this.styleSet = {
        width: width + 'px',
        height: this.contentHeight + 'px'
      }
      if (this.curChart) {
        this.$nextTick(this.initCharts)
      }
    },
    edit() {
      this.$emit('edit', this.id)
    },
    reset() {
      const t = {
        chartType: this.item.ChartType,
        Title: this.item.Title,
        YAxis: this.item.YAxis,
        XAxis: this.item.XAxis,
        MarkLine: this.item.MarkLine,
        Legend: this.item.Legend,
        IsStack: this.item.IsStack ?? false
      }
      this.control = t
      if (this.item.IsConfig) {
        this.$nextTick(this.calculate)
      }
    },
    async calculate() {
      const res = await Chart({
        Id: this.id,
        Search: this.search,
        Extend: this.extend
      })
      this.source = res
      this.initCharts()
    },
    initCharts() {
      if (this.curChart != null) {
        this.curChart.dispose()
      }
      const e = this.$refs.chartBody
      const myChart = this.$echarts.init(e, this.isDark ? 'dark' : 'light')
      this.curChart = myChart
      const option = {
        backgroundColor: 'transparent',
        title: {
          show: false,
          text: this.title,
          subtext: this.show,
          left: 'center'
        },
        legend: {
          orient: 'vertical',
          left: 'left'
        }
      }
      if (this.control.Title != null && this.control.Title.Show != null) {
        const title = this.control.Title
        option.title.show = title.Show
        option.title.top = 5
        if (title.Align === 0) {
          option.title.left = 'left'
        } else if (title.Align === 1) {
          option.title.left = 'center'
        } else if (title.Align === 2) {
          option.title.left = 'right'
        }
      }
      if (this.control.Legend != null && this.control.Legend.Show != null) {
        const legend = this.control.Legend
        option.legend.show = legend.Show
        if (legend.Position === 0) {
          option.legend.orient = 'vertical'
          option.legend.left = 'left'
        } else if (legend.Position === 1) {
          option.legend.orient = 'vertical'
          option.legend.left = 'left'
          option.legend.top = 'bottom'
        } else if (legend.Position === 2) {
          option.legend.orient = 'horizontal'
          option.legend.left = 'center'
        } else if (legend.Position === 3) {
          option.legend.orient = 'horizontal'
          option.legend.left = 'center'
          option.legend.top = 'bottom'
        } else if (legend.Position === 4) {
          option.legend.orient = 'vertical'
          option.legend.left = 'right'
        } else if (legend.Position === 5) {
          option.legend.orient = 'vertical'
          option.legend.left = 'right'
          option.legend.top = 'bottom'
        }
      }
      if (this.control.chartType === 0) {
        this.initPie(option)
      } else if (this.control.chartType === 2) {
        this.initLine(option, false)
      } else if (this.control.chartType === 1) {
        this.initBar(option)
      } else if (this.control.chartType === 3) {
        this.initStripe(option)
      } else if (this.control.chartType === 4) {
        this.initLine(option, true)
      } else if (this.control.chartType === 5) {
        this.initScatter(option, true)
      }
      myChart.setOption(option)
    },
    initScatter(option) {
      const segment = this.source.Segment
      option.grid = {
        left: '3%',
        right: '80px',
        bottom: '50px',
        containLabel: true
      }
      const that = this
      option.tooltip = {
        formatter: function(params) {
          if (segment.length === 1) {
            return params.seriesName + ' :<br/>' + segment[0].Value + ' : ' + params.value[0] + (that.control.XAxis && that.control.XAxis.Unit != null ? that.control.XAxis.Unit : '')
          } else {
            return params.seriesName + ':<br/>' + segment[0].Value + ' : ' + params.value[0] + (that.control.XAxis && that.control.XAxis.Unit != null ? that.control.XAxis.Unit : '') + '<br/>' + segment[1].Value + ' : ' + params.value[1] + (that.control.YAxis && that.control.YAxis.Unit != null ? that.control.YAxis.Unit : '')
          }
        }
      }
      option.toolbox = {
        feature: {
          dataZoom: {},
          brush: {
            type: ['rect', 'polygon', 'clear']
          }
        }
      }
      option.brush = {}
      option.legend.selectedMode = true
      option.legend.data = []
      const yAxis = {
        type: 'value',
        name: segment[1].Value,
        scale: true,
        splitLine: {
          show: false
        }
      }
      if (this.control.YAxis != null) {
        const y = this.control.YAxis
        yAxis.minInterval = y.MinInterval ?? 1
        yAxis.maxInterval = y.MaxInterval
        if (this.control.YAxis.Unit != null) {
          yAxis.axisLabel = {
            formatter: '{value} ' + this.control.YAxis.Unit
          }
        }
      }
      option.yAxis = [yAxis]
      const xAxis = {
        type: 'value',
        name: segment[0].Value,
        scale: true,
        splitLine: {
          show: false
        }
      }
      if (this.control.XAxis != null && this.control.XAxis.Unit != null) {
        xAxis.axisLabel = {
          formatter: '{value} ' + this.control.XAxis.Unit
        }
      }
      option.xAxis = [xAxis]
      option.series = []
      const x = segment[0].Key
      const y = segment[1].Key
      if (this.source.Legend && this.source.XLabel) {
        option.legend.show = true
        const one = this.source.XLabel.Name
        const two = this.source.Legend.Name
        this.source.XLabel.Label.forEach(c => {
          this.source.Legend.Label.forEach(a => {
            const list = this.source.Rows.filter(b => b[one].toString() === c.Key.toString() && b[two].toString() === a.Key.toString())
            if (list.length > 0) {
              const name = c.Value + ' ' + a.Value
              option.legend.data.push(name)
              option.series.push({
                name: name,
                type: 'scatter',
                emphasis: {
                  focus: 'series'
                },
                data: list.map(b => {
                  return [b[x], b[y]]
                })
              })
            }
          })
        })
      }
    },
    getMarkLine(colId, isYAxis) {
      if (this.control.MarkLine && this.control.MarkLine[colId] != null) {
        const line = this.control.MarkLine[colId]
        const t = {
          label: {
            show: true,
            symbols: 'circle',
            formatter: (e) => {
              return e.name ? e.name : e.value
            }
          },
          data: []
        }
        if (line.ValueType === 0) {
          line.Value.forEach(c => {
            t.data.push({
              yAxis: isYAxis ? c.Value : null,
              xAxis: isYAxis ? null : c.Value,
              name: c.Label,
              lineStyle: {
                color: c.Color
              }
            })
          })
        } else {
          t.lineStyle = {
            color: line.Color
          }
          if (line.ValueType === 1) {
            t.data.push({
              type: 'max',
              name: line.Label
            })
          } else if (line.ValueType === 2) {
            t.data.push({
              type: 'min',
              name: line.Label
            })
          } else if (line.ValueType === 3) {
            t.data.push({
              type: 'average',
              name: line.Label
            })
          } else if (line.ValueType === 4) {
            t.data.push([{ type: 'min', name: line.Label }, { type: 'max' }])
          }
        }
        return t
      }
      return null
    },
    initLine(option, isArea) {
      option.tooltip = {
        trigger: 'axis'
      }
      option.xAxis = {
        type: 'category',
        boundaryGap: true,
        data: this.source.XLabel.Label.map(c => c.Value)
      }
      option.yAxis = {
        type: 'value',
        minInterval: 1,
        max: (value) => {
          return value.max + 1
        }
      }
      if (this.source.Legend == null) {
        option.legend.data = this.source.Segment.map(c => c.Value)
        const key = this.source.XLabel.Name
        option.series = this.source.Segment.map(c => {
          const item = {
            name: c.Value,
            type: 'line',
            stack: this.control.IsStack ? 'Total' : null,
            markLine: this.getMarkLine(c.Id, true),
            data: this.source.XLabel.Label.map(a => {
              const row = this.source.Rows.find(b => b[key].toString() === a.Key)
              if (row == null || row[c.Key] == null) {
                return null
              }
              return row[c.Key]
            })
          }
          if (isArea) {
            item.areaStyle = {}
            item.emphasis = {
              focus: 'series'
            }
          }
          return item
        })
      } else {
        option.legend.data = this.source.Legend.Label.map(c => c.Value)
        const key = this.source.XLabel.Name
        const cache = {}
        const name = this.source.Legend.Name
        const valKey = this.source.Segment[0].Key
        const n = this.source.Segment[0].Value
        option.legend.formatter = (name) => {
          return name + n
        }
        this.source.Legend.Label.forEach(c => {
          const rows = this.source.Rows.filter(a => a[name] === c.Key)
          cache[c.Key] = this.source.XLabel.Label.map(a => {
            const row = rows.find(b => b[key].toString() === a.Key)
            if (row == null || row[valKey] == null) {
              return null
            }
            return row[valKey]
          })
        })
        const id = this.source.Legend.Id
        option.series = this.source.Legend.Label.map(c => {
          const item = {
            name: c.Value,
            type: 'line',
            stack: this.control.IsStack ? 'Total' : null,
            markLine: this.getMarkLine(id, true),
            data: cache[c.Key]
          }
          if (isArea) {
            item.areaStyle = {}
            item.emphasis = {
              focus: 'series'
            }
          }
          return item
        })
      }
      if (this.control.YAxis != null) {
        const y = this.control.YAxis
        option.yAxis.minInterval = y.MinInterval ?? 1
        option.yAxis.maxInterval = y.MaxInterval
      }
    },
    initPie(option) {
      option.tooltip = {
        trigger: 'item'
      }
      const key = this.source.Segment[0].Key
      const label = this.source.XLabel
      option.series = [{
        name: this.source.Segment[0].Value,
        type: 'pie',
        radius: '70%',
        data: this.source.Rows.map(c => {
          const v = c[label.Name] + ''
          const t = label.Label.find(a => a.Key === v)
          return {
            name: t.Value,
            value: c[key]
          }
        })
      }]
    },
    initBar(option) {
      option.tooltip = {
        trigger: 'axis'
      }
      option.xAxis = {
        type: 'category',
        boundaryGap: true,
        data: this.source.XLabel.Label.map(c => c.Value)
      }
      option.yAxis = {
        type: 'value',
        minInterval: 1,
        max: (value) => {
          return value.max + 1
        }
      }
      if (this.source.Legend == null) {
        option.legend.data = this.source.Segment.map(c => c.Value)
        const key = this.source.XLabel.Name
        option.series = this.source.Segment.map(c => {
          return {
            name: c.Value,
            type: 'bar',
            markLine: this.getMarkLine(c.Id, true),
            data: this.source.XLabel.Label.map(a => {
              const row = this.source.Rows.find(b => b[key].toString() === a.Key)
              if (row == null || row[c.Key] == null) {
                return null
              }
              return row[c.Key]
            })
          }
        })
      } else {
        option.legend.data = this.source.Legend.Label.map(c => c.Value)
        const key = this.source.XLabel.Name
        const cache = {}
        const name = this.source.Legend.Name
        const valKey = this.source.Segment[0].Key
        const n = this.source.Segment[0].Value
        option.legend.formatter = (name) => {
          return name + n
        }
        this.source.Legend.Label.forEach(c => {
          const rows = this.source.Rows.filter(a => a[name] === c.Key)
          cache[c.Key] = this.source.XLabel.Label.map(a => {
            const row = rows.find(b => b[key].toString() === a.Key)
            if (row == null || row[valKey] == null) {
              return null
            }
            return row[valKey]
          })
        })
        const id = this.source.Legend.Id
        option.series = this.source.Legend.Label.map(c => {
          return {
            name: c.Value,
            type: 'bar',
            markLine: this.getMarkLine(id, true),
            data: cache[c.Key]
          }
        })
      }
      if (this.control.YAxis != null) {
        const y = this.control.YAxis
        option.yAxis.minInterval = y.MinInterval ?? 1
        option.yAxis.maxInterval = y.MaxInterval
      }
    },
    initStripe(option) {
      option.tooltip = {
        trigger: 'axis',
        axisPointer: {
          type: 'shadow'
        }
      }
      option.yAxis = {
        type: 'category',
        data: this.source.XLabel.Label.map(c => c.Value)
      }
      option.xAxis = {
        type: 'value',
        boundaryGap: true,
        minInterval: 1,
        max: (value) => {
          return value.max + 1
        }
      }
      if (this.source.Legend == null) {
        option.legend.data = this.source.Segment.map(c => c.Value)
        const key = this.source.XLabel.Name
        option.series = this.source.Segment.map(c => {
          return {
            name: c.Value,
            type: 'bar',
            markLine: this.getMarkLine(c.Id, false),
            data: this.source.XLabel.Label.map(a => {
              const row = this.source.Rows.find(b => b[key].toString() === a.Key)
              if (row == null || row[c.Key] == null) {
                return null
              }
              return row[c.Key]
            })
          }
        })
      } else {
        option.legend.data = this.source.Legend.Label.map(c => c.Value)
        const key = this.source.XLabel.Name
        const cache = {}
        const name = this.source.Legend.Name
        const valKey = this.source.Segment[0].Key
        const n = this.source.Segment[0].Value
        option.legend.formatter = (name) => {
          return name + n
        }
        this.source.Legend.Label.forEach(c => {
          const rows = this.source.Rows.filter(a => a[name] === c.Key)
          cache[c.Key] = this.source.XLabel.Label.map(a => {
            const row = rows.find(b => b[key].toString() === a.Key)
            if (row == null || row[valKey] == null) {
              return null
            }
            return row[valKey]
          })
        })
        const id = this.source.Legend.Id
        option.series = this.source.Legend.Label.map(c => {
          return {
            name: c.Value,
            type: 'bar',
            markLine: this.getMarkLine(id, false),
            data: cache[c.Key]
          }
        })
      }
      if (this.control.YAxis != null) {
        const y = this.control.YAxis
        option.yAxis.minInterval = y.MinInterval ?? 1
        option.yAxis.maxInterval = y.MaxInterval
      }
    }
  }
}
</script>

<style scoped>
.control .null {
  text-align: center;
}

.control .chartBody {
  width: 100%;
  height: 100%;
}
</style>
